; (acumula-com-filtro combinador nulo f a prox b filtro)

(define (acumula-com-filtro combinador nulo f a prox b filtro)
  (if (> a b)
      nulo
      (if (filtro a)
          (combinador (f a)
                      (acumula-com-filtro combinador nulo f (prox a) prox b filtro))
          (acumula-com-filtro combinador nulo f (prox a) prox b filtro))))

; a. Assumindo que temos prime? (definições abaixo) então:

(define (soma-quadrados-dos-primos-entre a b)
  (acumula-com-filtro + 0 quadrado a (lambda (x) (+ x 1)) b prime?))

(define (quadrado x) (* x x))

; Definições para prime?

(define (smallest-divisor n)
  (find-divisor n 2))
(define (find-divisor n test-divisor)
  (cond ((> (quadrado test-divisor) n) n)
        ((divides? test-divisor n) test-divisor)
        (else (find-divisor n (+ test-divisor 1)))))
(define (divides? a b)
  (= (remainder b a) 0))

(define (prime? n)
  (= n (smallest-divisor n)))

; b.

(define (produto-inteiros-positivos-menores-que-e-primos-com n)
  (define (primo-com-n? a)
    (= (mdc a n) 1))
  (acumula-com-filtro * 1 identity 1 (lambda (x) (+ x 1)) (- n 1) primo-com-n?))

; Definição do MDC

(define (mdc a b)
  (if (= b 0)
      a
      (mdc b (remainder a b))))